package com.google.code.mochaccino.framework.xml.jaxb;
/*
 * Copyright 2012 Claude Houle claude.houle@gmail.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.net.URL;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;

/**
 * This classes contains a collection of JAXB Utilities for handling
 * of jaxb marshalling, unmarshalling, etc.
 */
public final class JAXBUtil {

	private static final Logger logger = LoggerFactory.getLogger( JAXBUtil.class );

	private JAXBUtil() {
	}

	/** Unmarhsall */
	@SuppressWarnings( "unchecked" )
	public static <T> T unmarshall( JAXBContext ctx, Class<T> type, Reader in ) throws JAXBException {
		if ( (ctx == null) && (type != null) ) {
			ctx = createContext( type );
		}
		if ( ctx == null ) {
			return null;
		}
		Unmarshaller reader = JAXBUtil.createUnmarshaller( ctx );
		T dsDef = (T) reader.unmarshal( in );
		return dsDef;
	}

	/** Create JAXB Context */
	public static <T> JAXBContext createContext( Class<T> clazz ) throws JAXBException {
		return JAXBContext.newInstance( clazz.getPackage().getName() );
	}

	/** Create Unmarshaller */
	public static <T> Marshaller createMarshaller( Class<T> clazz ) throws JAXBException {
		return createMarshaller( createContext( clazz ) );
	}

	/** Create Marshaller for Class */
	public static <T> Marshaller createMarshaller( Class<T> clazz, boolean indent ) throws JAXBException {
		return createMarshaller( createContext( clazz ), indent );
	}

	/** Create Marshaller */
	public static Marshaller createMarshaller( JAXBContext ctx ) throws JAXBException {
		return createMarshaller( ctx, true );
	}

	/** Create Marshaller */
	public static Marshaller createMarshaller( JAXBContext ctx, boolean indent ) throws JAXBException {
		Marshaller marshaller = ctx.createMarshaller();
		marshaller.setProperty( "jaxb.formatted.output", indent );
		return marshaller;
	}

	/** Create Unmarshaller */
	public static <T> Unmarshaller createUnmarshaller( Class<T> clazz ) throws JAXBException {
		return createUnmarshaller( createContext( clazz ) );
	}

	/** Create Unmarshaller */
	public static Unmarshaller createUnmarshaller( JAXBContext ctx ) throws JAXBException {
		Unmarshaller marshaller = ctx.createUnmarshaller();
		return marshaller;
	}

	/** Marshall */
	public static <T> String marshall( JAXBContext ctx, T obj ) throws JAXBException {
		StringWriter out = new StringWriter();
		marshall( ctx, obj, out );
		out.flush();
		try {
			out.close();
		} catch ( IOException e ) {
			if ( logger.isErrorEnabled() ) {
				logger.error( e.getMessage(), e );
			}
		}
		return out.toString();
	}

	/** Marshall */
	public static <T> void marshall( JAXBContext ctx, T obj, Writer out ) throws JAXBException {
		Marshaller marshaller = createMarshaller( ctx );
		marshaller.marshal( obj, out );
	}

	/** Marshall */
	public static <T> void marshall( JAXBContext ctx, T obj, File out ) throws JAXBException {
		Marshaller marshaller = createMarshaller( ctx );
		marshaller.marshal( obj, out );
	}

	/** Marshall */
	public static <T> void marshall( JAXBContext ctx, T obj, File out, boolean indent ) throws JAXBException {
		Marshaller marshaller = createMarshaller( ctx );
		marshaller.setProperty( "jaxb.formatted.output", indent );
		marshaller.marshal( obj, out );
	}

	/** Marshall */
	public static <T> void marshall( JAXBContext ctx, T obj, Node out ) throws JAXBException {
		Marshaller marshaller = createMarshaller( ctx );
		marshaller.marshal( obj, out );
	}

	/** Marshall */
	public static <T> void marshall( JAXBContext ctx, T obj, OutputStream out ) throws JAXBException {
		Marshaller marshaller = createMarshaller( ctx );
		marshaller.marshal( obj, out );
	}

	/** Marshall */
	public static <T> void marshall( JAXBContext ctx, T obj, OutputStream out, boolean indent ) throws JAXBException {
		Marshaller marshaller = createMarshaller( ctx );
		marshaller.setProperty( "jaxb.formatted.output", indent );
		marshaller.marshal( obj, out );
	}

	/** Marshall */
	public static <T> void marshall( JAXBContext ctx, T obj, Writer out, boolean indent ) throws JAXBException {
		Marshaller marshaller = createMarshaller( ctx );
		marshaller.setProperty( "jaxb.formatted.output", indent );
		marshaller.marshal( obj, out );
	}

	/** Unmarshall */
	public static <T> T unmarshall( JAXBContext ctx, Class<T> type, File in ) throws IOException, JAXBException {
		return unmarshall( ctx, type, new BufferedReader( new FileReader( in ) ) );
	}

	/** Unmarhsall */
	public static <T> T unmarshall( JAXBContext ctx, Class<T> type, InputStream in ) throws JAXBException {
		return unmarshall( ctx, type, new InputStreamReader( in ) );
	}

	/** Unmarhsall */
	public static <T> T unmarshall( JAXBContext ctx, Class<T> type, URL in ) throws IOException, JAXBException {
		return unmarshall( ctx, type, new BufferedReader( new FileReader( new File( in.getFile() ) ) ) );
	}
}
